home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / msdos / raytrace / pov / gen / plant05 / plant050.cpp < prev   
C/C++ Source or Header  |  1993-10-07  |  28KB  |  631 lines

  1. /*****************************************************************************         
  2.  Program : PLANT.EXE v0.50a
  3.  Purpose : Create plant-like objects for PoV Ray v1.0 and v2.0 and Polyray v1.6 
  4.            raytracers and also export to CTDS format.   
  5.  Created : 9/28/93
  6.  By      : Rob Bryerton CIS [73747,433]           
  7.  File    : PLANT050.CPP
  8.  Compiler: Microsoft C++ v8.00  
  9.  Model   : Small
  10.  Comments: Creates 'organic' plant-like objects using spheres...
  11.  
  12. *****************************************************************************/                           
  13.  
  14. #include <graph.h>              //  for graphics functions
  15. #include <stdlib.h>             //  for srand(), rand()
  16. #include <time.h>               //  for randomize()
  17. #include <math.h>               //  for sin(), cos()
  18. #include <conio.h>              //  for getch()
  19. #include <fstream.h>            //  for disk access, cin, cout, etc
  20. #include <string.h>             //  for strcpy()
  21. #include <float.h>              //  for FLT_MIN, FLT_MAX, etc 
  22.  
  23. #define VERSION  "0.50a"
  24. #define GREEN 2                 //  color indices
  25. #define RED 4
  26. #define LIGHTGREEN 10
  27. #define YELLOW 14
  28.  
  29. enum bool {FALSE, TRUE};
  30. enum Format {POV2,POV1,POLY,CTDS};
  31.  
  32. struct Vector{ double x,y,z;};
  33.  
  34. void calc_bounds(void);
  35. void calc_branch(int size, double theta, double x, double y);
  36. void calc_cluster(int size, double x, double y);
  37. void close_display(void);
  38. void end_run(void);
  39. void get_inputs(void);
  40. void init_display(int v_mode); 
  41. void new_union(void);
  42. void process_args (int argc, char* argv[]);
  43. void process_option (char* s);
  44. void reset_bounds(void);
  45. void set_precision(char* prec);
  46. void show_title(void);
  47. void usage(void);
  48. void write_header(void);
  49. void write_piece(void);   
  50. void write_union_end(void);
  51. void write_end(void);
  52.  
  53. Format    format = POV2;       // default output 
  54. bool      spheres_only = FALSE; // write spheres and cones
  55. bool      nest_bounds = FALSE; 
  56. bool      bound_sum = FALSE;    // include bound stats w/ each bound written
  57. bool      display = FALSE;     // ****** change to FALSE for release version
  58. bool      extended = FALSE;    // ****** change to FALSE for release version
  59. bool      write_texture=TRUE; // write texture on EACH segment...choose from 4 colors
  60. int       v_mode=0;           // ****** change to 0 for release version
  61. long      bound_val=30,bound_count=0;// bnd every ...and count # bounds written for next nested
  62. long      total_bounds = 1;  // start w/1 for default global bounding box
  63. long      counter=0;         // total # of objects written
  64. char      com[3] = "//";     // default comment char
  65. char      filename[80];      // outfile name
  66. char      union_name[80];    // for output file union name
  67. char      format_name[20];    // for FORMAT statement in output file 
  68. char      buff[257];         // general use buffer
  69. char      texture[80];
  70. char      prev_texture[80];  // the one b/4 texture !
  71. clock_t   start, finish;  // ******** 2 lines for timer
  72. double    duration;   
  73. double    basic_rad = 1.0,sphere_rad=1.0;  // basic radius and current sphere radius
  74. double    bound_radi = 0.0;     // current max sph. radius for bound info
  75. double    prev_sphere_rad,max_radius; // radii
  76. double    ht_scale = 1.0; // flat or tall plant
  77. double    internal_scale, user_scale, overall_scale;  // fixes numbers so object is 10 units 
  78. Vector    ray = {0.0, 0.0, 0.0};  // outfile vector
  79. Vector    prev_ray = {0.0, 0.0, 0.0};
  80. Vector    min  = {FLT_MAX, FLT_MAX, FLT_MAX};     // for nested bounding info
  81. Vector    max  = {FLT_MIN, FLT_MIN, FLT_MIN};     
  82. Vector    gmin = {FLT_MAX, FLT_MAX, FLT_MAX};  // for scene extent and 
  83. Vector    gmax = {FLT_MIN, FLT_MIN, FLT_MIN};  // global bounding info
  84.  
  85. ofstream  outfile;    //  these vars are used for basic shape calculations
  86. double    pi=3.1415926535897932384626; //  pi ...lower #'s change 'radius' of plant
  87. int       nume=30;            //  numerator of probability ...left or rite ?
  88. int       denom=100;          //  denominator of prob.
  89. int       number=4;           //  number of branches per cluster
  90. double    rad=4.5;            //  length of straight line segments
  91. double    deltheta=0.1;       //  change in THETA (radians)    
  92. int       segs=60;            //  max objects & line segments per branch
  93. int       size=60;
  94.  
  95. int       max_write_len=60;   // disregard any piece longer than this number
  96.  
  97. double    redux=3.0;          //  how much to divide # of segments...lower # means finer 'res.' (more objects)
  98. int       min_len=1;          //  min # of line segments (spheres per branch)
  99. int       x,y;                //  display vector...object vector is derived from this also
  100.  
  101.  
  102.  
  103. //main
  104. int main(int argc, char* argv[])             
  105. {   
  106.     if(argc>1)process_args (argc, argv);    
  107.     
  108.     show_title(); 
  109.     get_inputs();               //  get user input and check for 'validity' 
  110.             
  111.     outfile.open(filename,ios::out);      // try to open disk file
  112.     if(! outfile)   exit(1);   // if disk access error,exit       
  113.     
  114.     if(display) init_display(v_mode);     // try to set graphics display 
  115.     
  116.     write_header();    
  117.     outfile.setf(ios::showpoint | ios::fixed); 
  118.     //outfile.precision(6);            
  119.     srand( (unsigned)time(NULL) );         //   seed random number    
  120.     
  121.     x=512,y=384;   //  set origin of cluster        
  122.     internal_scale = 0.1111;                     // default object size is 
  123.     overall_scale  = internal_scale*user_scale;  // approx.10x10x10
  124.     size = segs;  
  125.     bound_val = segs*0.5; // seems to be the best figure as far as rendering
  126.                           //    speed and bound accuracy are concerned 
  127.     if(bound_val < 20) bound_val = 20; // don't want too many bounds
  128.                          
  129.     if(display)  cerr << "TOP VIEW (XZ)\n"; 
  130.     cerr << "\nCalculating object... Press any key to abort\n\n";
  131.      start = clock(); // ****************** start timer
  132.  
  133.     calc_cluster(size, x, y);          // calculate plant and show progress 
  134.    
  135.     if(format != CTDS) write_union_end(); // write final nested bound if nec.     
  136.     write_end(); 
  137.     outfile.close;          //  close disk file  
  138.     finish = clock();    // *********************  stop timer
  139.     duration = (double)(finish - start) / CLOCKS_PER_SEC;  // *** calc. time
  140.     
  141.     if(display) {
  142.      cerr << "Press any key to continue...";
  143.      getch();                        //  wait for keypress
  144.      close_display();    //  restore video to previous state
  145.     }       
  146.     cout << endl << counter << " objects used to create " << filename;
  147.     cout << "\nCalculation time : "<<duration<< " seconds\n"; // show time
  148.     return(0);
  149. }
  150.  
  151. /******************************                    **************************
  152. ****************************** FUNCTION DEFINITIONS *************************
  153.  ******************************                    *************************/
  154.         
  155. void calc_bounds()
  156. {
  157.     // compute min and max object vectors for current bounding box if needed
  158.  if(format != CTDS && nest_bounds){  
  159.    min.x = __min(min.x,ray.x);
  160.    max.x = __max(max.x,ray.x);
  161.    min.y = __min(min.y,ray.y);
  162.    max.y = __max(max.y,ray.y);
  163.    min.z = __min(min.z,ray.z);
  164.    max.z = __max(max.z,ray.z);      
  165.  }                        
  166.            
  167.    gmin.x = __min(gmin.x,ray.x);    // now globally
  168.    gmax.x = __max(gmax.x,ray.x);
  169.    gmin.y = __min(gmin.y,ray.y);
  170.    gmax.y = __max(gmax.y,ray.y);
  171.    gmin.z = __min(gmin.z,ray.z);
  172.    gmax.z = __max(gmax.z,ray.z);
  173. }        
  174.        
  175. void calc_branch(int size, double theta, double x, double y)
  176. {
  177.     for(int j=0; j<size; j++)
  178.     {                                   //  get rand. #, range 0 to denom
  179.         int randy = rand() % denom;
  180.         int chng = (randy<nume) ? -1 : 1;   //  left or right ??
  181.         theta = theta + chng * deltheta;    //  new angle
  182.         x = x + rad*sin(theta);             //  x and y  
  183.         y = y + rad*cos(theta);             //   of next point  
  184.      if (size <= max_write_len ){  // this decides whether or not
  185.                                    // to execute next statements
  186.       /*************************************************************/              
  187.         if(size</*4*/(segs*0.0667)){ ray.y =j+(segs-3)+(segs/redux)+((segs/redux)/redux);  
  188.               if(display) _setcolor(RED); 
  189.               if(j==0) strcpy(texture,"flower_tex"); 
  190.               sphere_rad = basic_rad*0.85;                     
  191.          } 
  192.         else if(size</*13*/(segs*0.22)){ ray.y =j+(segs-2)+(segs/redux);         
  193.               if(display) _setcolor(YELLOW); 
  194.               if(j==0) strcpy(texture,"sub_branch_tex"); 
  195.               sphere_rad = basic_rad*1.2;                    
  196.          } 
  197.         else if(size</*40*/(segs*0.675)){ ray.y =j+(segs-1);             
  198.               if(display) _setcolor(LIGHTGREEN); 
  199.               if(j==0) strcpy(texture,"branch_tex");
  200.               sphere_rad = basic_rad*1.6;               
  201.          }
  202.         else{ ray.y =j;
  203.               if(display) _setcolor(GREEN);  //dk green
  204.               if(j==0) strcpy(texture,"stem_tex");
  205.               sphere_rad = basic_rad*2.0;                       
  206.          }       
  207.         if(display){
  208.           if(! write_texture) _setcolor(GREEN);  //no textures, right??
  209.           if     (v_mode==1) _lineto(int(x*0.625),int(y*0.625)); 
  210.           else if(v_mode==2) _lineto(int(x*0.78125),int(y*0.78125)); 
  211.           else               _lineto(int(x),int(y));  // draw line                        
  212.         } 
  213.                 
  214.         ray.x = ((double)(x-512)*0.3)*overall_scale;  // translate sizes to
  215.         ray.z = ((double)(y-384)*0.3)*overall_scale;  // file sizes based on      
  216.         ray.y = ray.y*overall_scale*ht_scale;         // scaling info...
  217.         sphere_rad *= overall_scale; 
  218.                 
  219.         if(counter==0){            //first time around only        
  220.           prev_sphere_rad = sphere_rad;            
  221.           max_radius = sphere_rad;
  222.         }             
  223.         bound_radi = prev_sphere_rad; //current bound, radius to add to bound
  224.                         
  225.         if((format != CTDS) &&                       // if it's POV or Polyray  AND  we're
  226.         (bound_count==bound_val /*&& nest_bounds*/ || //ready for a bound OR....
  227.          prev_sphere_rad != sphere_rad /*&& nest_bounds*/)// the sphere radius changed...  
  228.         ){                                           //  so it's time for a new bound
  229.           write_union_end();          
  230.           new_union();
  231.           if(nest_bounds){   // added IF
  232.             total_bounds++; 
  233.             reset_bounds();                        
  234.           }                            
  235.           bound_count=1;
  236.           write_piece();
  237.         }
  238.         else { 
  239.           bound_count++; 
  240.           write_piece();
  241.         }                
  242.         strcpy(prev_texture, texture);
  243.         prev_sphere_rad = sphere_rad;
  244.         prev_ray.x = ray.x; 
  245.         prev_ray.y = ray.y; 
  246.         prev_ray.z = ray.z;
  247.          
  248.         calc_bounds();     
  249.         counter++;                             // increment object count
  250.     } 
  251.   /***************************************************/                         
  252.   }
  253.     if(size>min_len)
  254.     {                                   //  if branch is long enough, 
  255.         int newsize = size / redux;     //  make a new one, but smaller
  256.         calc_cluster(newsize,x,y);      //  than before.
  257.     }
  258. }
  259.  
  260. void calc_cluster(int size, double x, double y)
  261. {
  262.     if( kbhit()) end_run();
  263.     
  264.     for(int i=0; i<number; i++)         //  for each branch
  265.     {
  266.         double theta = i * 2 * pi / number;    
  267.         
  268.         if(display){        
  269.           if     (v_mode==1) _moveto(int(x*0.625),int(y*0.625));
  270.           else if(v_mode==2) _moveto(int(x*0.78125),int(y*0.78125)); 
  271.           else               _moveto(int(x),int(y));  // get set to draw next line          
  272.         }     
  273.         
  274.                               //  make a branch
  275.         calc_branch(size, theta, x, y);        
  276.     }
  277. }
  278.  
  279.  
  280. void close_display()    
  281. {
  282.    _setvideomode(_DEFAULTMODE);    //  restore video to previous state
  283. }       
  284.  
  285. void end_run()
  286.    if(format != CTDS) write_union_end();
  287.    write_end();    
  288.    if(display)   close_display();      
  289.    cerr << "\n--RUN ABORTED--\n";
  290.    cout << counter << " objects used to create " << filename << endl;
  291.    
  292.    exit(1);
  293. }   
  294.    
  295.  
  296. void get_inputs() 
  297. {   
  298.  double noise=1.0,pi_distort=1.0,sphere_mult=1.0,denom_mult=1.0;
  299.     
  300.     cout<< "\n1\tPOV 2.0\n2\tPOV 1.0\n3\tPolyray\n4\tCTDS\n" << "Number for format? [1]: ";
  301.         cin.getline(buff,256);        int choice = atoi(buff);         
  302.     switch(choice){        // output format
  303.       case 2 : format = POV1;  strcpy(format_name,"POV-Ray v1.0"); break;
  304.       case 3 : format = POLY;  strcpy(format_name,"Polyray v1.6"); break;  
  305.       case 4 : format = CTDS;  strcpy(format_name,"CTDS");         break;                   
  306.       default: format = POV2;  strcpy(format_name,"POV-Ray v2.0");     
  307.     }                 
  308.     cout << "Ouput filename? [plant.inc]: ";
  309.         cin.getline(buff,256);           strcpy(filename,buff);
  310. if(format != CTDS){
  311.     cout << "Union name? [plant]: ";
  312.         cin.getline(buff,256);           strcpy(union_name,buff);   }        
  313.     cout << "Number of branches (recursive) ? [4]:";
  314.         cin.getline(buff,256);           number = atoi(buff);    
  315.     cout << "Maximum # of spheres per branch ? [60]:";
  316.         cin.getline(buff,256);           segs = atoi(buff);   if(segs==0) segs = 60;                                                
  317.     cout << "Minimum # of spheres per branch ? [1]:";
  318.         cin.getline(buff,256);           min_len = atoi(buff); 
  319. if(extended) {                                                 
  320.     cout << "Disregard branches longer than ? [" <<segs<< "]:";
  321.         cin.getline(buff,256);           max_write_len = atoi(buff);  
  322.     cout << "Divide branches by ? [3.0]:";
  323.         cin.getline(buff,256);           redux = atof(buff);  
  324.     cout << "Radial distortion (PI * x)  ? [1.0]:";
  325.         cin.getline(buff,256);           pi_distort = atof(buff);     
  326.     cout << "Branch rotation factor ? [1.0]:";
  327.         cin.getline(buff,256);           denom_mult = atof(buff);    
  328.     cout << "Overall noise factor ? [1.0]:";
  329.         cin.getline(buff,256);           noise = atof(buff);    
  330.     cout << "Height scaling  ? [1.0]:";
  331.         cin.getline(buff,256);           ht_scale = atof(buff); 
  332.     cout << "Sphere scaling  ? [1.0]:";
  333.         cin.getline(buff,256);           sphere_mult = atof(buff);   }                                                
  334.     cout << "Global scaling  ? [1.0]: ";
  335.         cin.getline(buff,256);           user_scale = atof(buff);
  336.     
  337.         // Set up default values if applicable
  338.     if(filename[0]=='\0') strcpy(filename,"plant.inc");
  339.     if(union_name[0]=='\0') strcpy(union_name,"plant");    
  340.     if(min_len==0) min_len = 1;              
  341.     if(denom_mult==0.0) denom_mult = 1.0; denom *= denom_mult;   
  342.     if(number==0) number = 4;       if(user_scale==0.0) user_scale = 1.0;
  343.     if(pi_distort==0.0) pi_distort = 1.0;  pi *= pi_distort;
  344.     if(noise==0.0) noise = 1.0;  deltheta *= noise;
  345.     /*if(segs==0) segs = 60;*/       if(max_write_len==0) max_write_len = segs;
  346.     if(redux==0.0) redux = 3.0;
  347.     if(ht_scale==0.0) ht_scale = 1.0;  
  348.     if(sphere_mult==0.0) sphere_mult = 1.0; basic_rad *= sphere_mult;
  349.     if(min_len == segs && max_write_len < min_len){ 
  350.         // this would cause a math error
  351.        min_len--; // not what user wanted, but better than a stack underflow!! 
  352.     }   
  353. }
  354.  
  355.  
  356. void init_display(int v_mode) 
  357. {     
  358.     switch(v_mode){
  359.         case 3  : if(!_setvideomode(_XRES16COLOR)) {cerr << "\nCouldn't set 1024x768 graphics mode... trying 800x600\n"; v_mode = 2;}
  360.                    else break;       /* 1024x768x16 */
  361.         case 2  : if(!_setvideomode(_SRES16COLOR)) {cerr << "\nCouldn't set 800x600 graphics mode... trying 640x480\n";  v_mode = 1;}
  362.                    else break;       /*  800x600x16 */ 
  363.         case 1  : if(!_setvideomode(_VRES16COLOR)) {cerr << "\nCouldn't set 640x480 graphics mode... continuing without display\n"; v_mode = 0;}
  364.                    else break;       /*  640x480x16 */
  365.         default : display = FALSE;   /*  no display */                
  366.      }              
  367. }
  368.  
  369.     
  370. void new_union()
  371. {  
  372.  
  373.   switch(format){
  374.    case POV1 :                 
  375.        outfile << " object{\n  union{\n"; break;
  376.    case POLY :                      
  377.        outfile << "+object{ \n";          break;
  378.    default   :    // POV2                              
  379.        outfile << " object{\n  union{\n";  
  380.   }
  381.        
  382.  
  383.  
  384. void process_args (int argc, char* argv[])
  385. {
  386.     for (int i = 1; i < argc; i++)
  387.     {
  388.         if (argv[i][0] == '-' || argv[i][0] == '/')
  389.             process_option (&argv[i][1]);
  390.         else
  391.         {usage();   exit(1);}
  392.     }
  393. }     
  394.  
  395.  
  396. void process_option (char* s)
  397. {
  398.     switch (toupper(s[0]))
  399.     {    
  400.     case 'B': nest_bounds = TRUE;    break; //def=FALSE, don't write bounds
  401.     case 'E': extended = TRUE;       break;
  402.     case 'O': spheres_only = TRUE;   break;
  403.     case 'P': set_precision(&s[1]);  break;
  404.     case 'D': display = TRUE; v_mode = atoi(&s[1]);  break;  //def=no display    
  405.     case 'S': bound_sum = TRUE;      break; //def=FALSE, global bound report only
  406.     case 'T': write_texture = FALSE; break; //def=TRUE, write textures
  407.     case '?': usage(); exit(0);
  408.     case 'H': usage(); exit(0);
  409.     default : usage(); exit(1);     
  410.     }
  411. }
  412.  
  413. void reset_bounds()
  414. {
  415.     min.x=FLT_MAX, min.y=FLT_MAX, min.z=FLT_MAX;  // 
  416.     max.x=FLT_MIN, max.y=FLT_MIN, max.z=FLT_MIN;  // reset for new bounding box
  417. }    
  418.  
  419. void set_precision(char* prec)
  420. {  
  421.     outfile.precision((atoi(prec) > 2 ? atoi(prec) : 6 ));  
  422. }
  423.  
  424. void show_title()
  425. {
  426.     cout << "\nPlant v"<< VERSION << ", Copyright (c) 1993 Rob Bryerton\n"    
  427.          << "Creates a data file of a plant-like object for the POV-Ray v1.0\n"
  428.          << "and v2.0 and Polyray v1.6 raytracers, and the Connect The Dots\n" 
  429.          << "Smoother (CTDS).\n";             
  430. }         
  431.     
  432. void write_header()
  433. {
  434.  if(format==CTDS){ strcpy(com,";"); strcpy(union_name,"-----");}
  435.    
  436.    outfile 
  437.     <<com<<" FILE: "<<filename<<"    UNION NAME: "<<union_name<<"    FORMAT: "<<format_name<< endl
  438.     <<com<<" This data file created by PLANT.EXE v"<<VERSION<<" for the POV-Ray v1.0 and\n"
  439.     <<com<<" v2.0 and Polyray v1.6 raytracers, and the Connect The Dots Smoother (CTDS).\n"  
  440.     <<com<<" ----------------SEE END OF LISTING FOR OBJECT EXTENTS----------------------\n\n";   
  441.  switch(format) {    
  442.   case POLY :                                    
  443.   if(write_texture) { 
  444.    outfile                               
  445.     << "include \"..\\colors.inc\"\n"
  446.     << "define stem_tex       texture{ matte { color <0.0, 0.65, 0.0> } }\n"
  447.     << "define branch_tex     texture{ matte { color <0.0, 0.8, 0.0> } }\n"
  448.     << "define sub_branch_tex texture{ matte { color yellow } }\n"
  449.     << "define flower_tex     texture{ matte { color red } }\n";     
  450.    }
  451.    outfile 
  452.     << "\ndefine " << union_name << endl
  453.     << "object{ \n object{\n";        
  454.     break;
  455.   case POV1  :    
  456.     outfile 
  457.     << "#declare stem_tex=       texture{ diffuse 0.7 color green 0.65  } \n";
  458.    if(write_texture) { 
  459.     outfile 
  460.      << "#declare branch_tex=     texture{ diffuse 0.7 color green 0.8  } \n"
  461.      << "#declare sub_branch_tex= texture{ diffuse 0.7 color Yellow } \n"
  462.      << "#declare flower_tex=     texture{ diffuse 0.7 color Red } \n";
  463.    }
  464.     outfile             
  465.      << "\n#declare "<<union_name<<" = composite{ \nobject{\n union{\n";
  466.      break;
  467.   default :      // POV2
  468.    if(write_texture) {    
  469.     outfile 
  470.      << "#declare stem_tex=       texture{ pigment{color green 0.65} finish{diffuse 0.7}  } \n"
  471.      << "#declare branch_tex=     texture{ pigment{color green 0.8}  finish{diffuse 0.7}  } \n"
  472.      << "#declare sub_branch_tex= texture{ pigment{color Yellow}     finish{diffuse 0.7}  } \n"
  473.      << "#declare flower_tex=     texture{ pigment{color Red}        finish{diffuse 0.7}  } \n";
  474.    }                                                                    
  475.    outfile             
  476.      << "\n#declare "<<union_name<<" = union{ \nobject{\n union{\n";
  477.  }
  478. }   
  479.  
  480. void write_piece()
  481. {       
  482.    switch(format){
  483.     case POLY :
  484.      if(counter !=0 && bound_count!=1) outfile << "   +"; //  for Polyray union 
  485.      else                              outfile << "    ";
  486.      if(counter==0 || bound_count == 1 || spheres_only) //       
  487.          outfile << "object{ sphere < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  488.      else{ 
  489.          outfile << "object{ sphere < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  490.          outfile << "   +object{ cone < " <<prev_ray.x<< ", " << prev_ray.y << ", " <<prev_ray.z<< " >, " << sphere_rad << ", < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  491.          counter++; bound_count++; //add another object to total         
  492.      }    
  493.         break;
  494.     case CTDS :         
  495.      if(sphere_rad != prev_sphere_rad) outfile << endl; //insert blank line for CTDS for each new sphere size for /m option
  496.      outfile << ray.x<< " " << ray.y << " " <<ray.z<< " " << sphere_rad << endl;
  497.      break;
  498.     case POV1 :     
  499.      outfile << "   sphere{ < " <<ray.x<< " " << ray.y << " " <<ray.z<< " > " << sphere_rad << " }\n";    
  500.      break;
  501.     default   :    // POV2
  502.       if(counter==0 || bound_count == 1 || spheres_only) //       
  503.          outfile << "   sphere{ < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  504.       else{ 
  505.          outfile << "   sphere{ < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  506.          outfile << "   cone{ < " <<prev_ray.x<< ", " << prev_ray.y << ", " <<prev_ray.z<< " >, " << sphere_rad << ", < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << " }\n";
  507.          counter++; bound_count++; //add another object to total
  508.       } // else 
  509.    }  // switch
  510. }   // function
  511.  
  512.  
  513.     
  514. void write_union_end()
  515. {          
  516.    Vector cbmin,cbmax; // current bound min and max vectors    
  517.    if(nest_bounds){       
  518.      cbmax.x = max.x + bound_radi;
  519.      cbmin.x = min.x - bound_radi;
  520.      cbmax.y = max.y + bound_radi;
  521.      cbmin.y = min.y - bound_radi;
  522.      cbmax.z = max.z + bound_radi;  
  523.      cbmin.z = min.z - bound_radi;  
  524.    } 
  525.             
  526.  switch(format){
  527.    case POLY :                 
  528.     if(write_texture) outfile << "  " << prev_texture << endl;  
  529.     if(nest_bounds){           
  530.            outfile << "  bounding_box < " <<cbmin.x<<", "<<cbmin.y<<", "<<cbmin.z<<" >,<"
  531.                                           <<cbmax.x<<", "<<cbmax.y<<", "<<cbmax.z<<" >\n";                                         
  532.     }
  533.     outfile << "  }";   // close the current union 
  534.     break;                                   
  535.    case POV1  :    
  536.     outfile << "  }\n"; // close the current union 
  537.     if(write_texture) outfile << " texture{ " << prev_texture << " }\n";
  538.     else              outfile << " texture{ stem_tex }\n";      
  539.     
  540.     if(nest_bounds){  outfile << " bounded_by{ \n"
  541.                               << "  box{ < " << cbmin.x<<" "<<cbmin.y<<" "<<cbmin.z << "> < "
  542.                                              << cbmax.x<<" "<<cbmax.y<<" "<<cbmax.z << "> }\n  }\n";  
  543.     }
  544.     outfile    << " }";   // close current object            
  545.     break;
  546.    default  :    // POV2
  547.     outfile << "  }\n";
  548.     if(write_texture) outfile << " texture{ " << prev_texture << " }\n";    
  549.     if(nest_bounds){  outfile << " bounded_by{ \n"
  550.                               << "  box{ < " << cbmin.x<<", "<<cbmin.y<<", "<<cbmin.z << ">, < "
  551.                                              << cbmax.x<<", "<<cbmax.y<<", "<<cbmax.z << "> }\n  }\n";
  552.                                            
  553.     }
  554.     outfile    << " }";   // close current object            
  555.   }  
  556.   if(bound_sum && nest_bounds){        
  557.     outfile <<com<<"          Current bounding box info...\n"        
  558.             <<com<<"                 Min. x : " << cbmin.x << endl
  559.             <<com<<"                      y : " << cbmin.y << endl
  560.             <<com<<"                      z : " << cbmin.z << endl
  561.             <<com<<"                 Max. x : " << cbmax.x << endl        
  562.             <<com<<"                      y : " << cbmax.y << endl         
  563.             <<com<<"                      z : " << cbmax.z; 
  564.   }               
  565.   outfile << endl;
  566. }   
  567.  
  568.  
  569. void write_end()
  570. {           
  571.     gmax.x += max_radius;   
  572.     gmin.x -= max_radius; 
  573.     gmax.y += max_radius;   
  574.     gmin.y -= max_radius; 
  575.     gmax.z += max_radius;
  576.     gmin.z -= max_radius;   
  577.  if(nest_bounds){         
  578.   switch(format){
  579.     case POLY :           
  580.      outfile << "  bounding_box < " <<gmin.x<<", "<<gmin.y<<", "<<gmin.z<<" >,<"
  581.                                     <<gmax.x<<", "<<gmax.y<<", "<<gmax.z<<" >\n";            
  582.     break;
  583.     case POV1 :
  584.      outfile << " bounded_by{\n"
  585.              << "  box{ < " << gmin.x<<" "<<gmin.y<<" "<<gmin.z << "> < "
  586.                             << gmax.x<<" "<<gmax.y<<" "<<gmax.z << "> }\n  }\n";
  587.     break;
  588.     default   : //POV2
  589.      outfile << " bounded_by{\n"
  590.              << "  box{ < " << gmin.x<<", "<<gmin.y<<", "<<gmin.z << ">, < "
  591.                             << gmax.x<<", "<<gmax.y<<", "<<gmax.z << "> }\n  }\n";                                 
  592.    } 
  593.   }
  594.   outfile << "}\n\n";     // close 'master' union 
  595.   // this next block is output for ALL formats w/the appropriate comment char's       
  596.  if(format != CTDS && nest_bounds){
  597.   outfile <<com<<" Bounds written...."<< total_bounds << endl;
  598.  }
  599.   outfile <<com<<" Objects written..."<< counter << endl << endl       
  600.           <<com<<"   Object extents are as follows...\n"        
  601.           <<com<<"     Min. x : " << gmin.x << endl
  602.           <<com<<"          y : " << gmin.y << endl
  603.           <<com<<"          z : " << gmin.z << endl
  604.           <<com<<"     Max. x : " << gmax.x << endl        
  605.           <<com<<"          y : " << gmax.y << endl         
  606.           <<com<<"          z : " << gmax.z << endl;
  607. }                
  608.     
  609.  
  610.  
  611. void usage()
  612. {
  613.     cerr << "\n                               Plant v" << VERSION << endl          
  614.         << "Usage: plant [options]\n"
  615.         << "Options:  -b    Write bounds in POV or Polyray output.\n" 
  616.         << "          -d#   enables 2D (xz) display of plant... # is the graphics mode.\n"        
  617.         << "                0=no display  1=640x480  2=800x600  3=1024x768  \n"
  618.         << "                Default value is 0.\n"
  619.         << "          -e    Gives you a menu with an extended choice of options.\n"                
  620.         << "          -o    Use spheres ONLY (no cones) in output file.\n"
  621.         << "          -p#   where # is the precision of the output file numbers.\n"
  622.         << "                Range is 3 - 9 with a default precision of 6 decimal places.\n" 
  623.         << "          -s    Include all bounding stats in output file. (POV and Polyray)\n"
  624.         << "          -t    Do NOT write textures in output file.\n"
  625.         << "\nType PLANT with no parameters for the default menus and options.\n";        
  626. }
  627.  
  628.  
  629.